home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of MacTutor - S…e Code for Volumes 1 to 5
/
The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin
/
Source Code
/
#41 (Feb 89)
/
security code
/
Globals.p
< prev
next >
Wrap
Text File
|
1988-11-29
|
35KB
|
1,485 lines
UNIT Globals;
{-------------------------------------------}
(*
©1988 by Steve Seaquist. All rights reserved.
Used by permission. Use at your own risk.
No warranty is expressed or implied.
This Macintosh virus-detecting program was
originally published and explained in the
February 1989 issue of MacTutor magazine.
Some aspects of its design are important to
security, and it uses some unusual
techniques, so please read the article.
*)
{-------------------------------------------}
INTERFACE
USES
MemTypes,QuickDraw,OSIntf,ToolIntf,
PackIntf;
CONST
{---- Low Mem Globals ----}
kCurApName = $910;
kCurApRefNum = $900;
kBootDrive = $210;
kResLoad = $A5E;
kScrDmpEnb = $2F8;
kSFCBLen = $3F6;
kSPConfig = $1FB;
kSysMap = $A58;
kSysResName = $AD8;
{---- Other constants ----}
kIOBufferSize = 10000;
kProcessSelf = FALSE;
kRsrcHdlValid = 9876543;
kRsrcIsInitd = 3456789;
kZeroOutVirs = TRUE;
TYPE
TCountsPtr = ^TCountsRec;
TCountsRec =
RECORD
fDeleted: LONGINT;
fExamined: LONGINT;
fFiles: LONGINT;
fInfected: LONGINT;
fRemoved: LONGINT;
fResources: LONGINT;
END;
TFeedbackPtr = ^TFeedbackRec;
TFeedbackRec =
PACKED RECORD
fWroteDirname: BOOLEAN;
fWroteFilename: BOOLEAN;
END;
TJTEHdl = ^TJTEPtr;
TJTEPtr = ^TJTERec;
TJTERec =
RECORD
fOffset: INTEGER;
fSkip3F3C: INTEGER;
fSegId: INTEGER;
fSkipA9F0: INTEGER;
END;
TJTHdl = ^TJTPtr;
TJTPtr = ^TJTRec;
TJTRec =
RECORD
fAboveA5Size: LONGINT;
fBelowA5Size: LONGINT;
fNbrBytesInTable: LONGINT;
fTableOffset: LONGINT;
fJTEntry:
ARRAY [1..1] OF TJTERec;
END;
TLoaded =
(eNotYet,eAlreadyLoaded,eWeLoadedIt);
TMainItem =
(eNotADlogItem,
eDirs,eDiry,eEvery,eFiles,eQuit,
eAwait,eBeeps,eFgPr,eFgPrC,
eLList,eRmVir,eTrace,
eMain,eOpts,eScOW,
eDBtn);
TMainOpt =
ARRAY [eAwait..eTrace] OF BOOLEAN;
TPaocRec =
PACKED ARRAY[1..1] OF CHAR;
TResIdOrIndex = (ResId,Index);
TRsrcPtr = ^TRsrcRec;
TRsrcRec =
RECORD
fFlag: LONGINT;
fHdl: Handle;
fInfected: BOOLEAN;
fKnown: BOOLEAN;
fLoaded: TLoaded;
fResAttrs: INTEGER;
fResId: INTEGER;
fResType: ResType;
fSize: Size;
fState: SignedByte;
END;
TScoresHdl = ^TScoresPtr;
TScoresPtr = ^TScoresRec;
TScoresRec =
RECORD
fOffsetToFirstJTE:INTEGER;
fNbrJTEsForRsrc: INTEGER;
fOldJTE: TJTERec;
END;
TWordHdl = ^TWordPtr;
TWordPtr = ^INTEGER;
VAR
gAAGlobals: SignedByte;
gAbortPatrol: BOOLEAN;
gActiveSelf: BOOLEAN;
gActiveSys: BOOLEAN;
gCode0: TRsrcRec;
gCounts: TCountsRec;
gCurrDInfo: DInfo;
gCurrDirId: LONGINT;
gCurrDirname: Str255;
gCurrEOF: LONGINT;
gCurrIOBuffer: Ptr;
gCurrFileDeleted: BOOLEAN;
gCurrFilename: Str255;
gCurrFInfo: FInfo;
gCurrIndex: INTEGER;
gCurrRefNum: INTEGER;
gCurrRsrc: TRsrcRec;
gCurrVRefNum: INTEGER;
gCurrWDRefNum: INTEGER;
gDateTimeRec: DateTimeRec;
gDisabled: TMainOpt;
gDlogPtr: DialogPtr;
gError: OSErr;
gEvt: EventRecord;
gEvtMask: INTEGER;
gFgPrTitle: Str255;
gGrafPtr: GrafPtr;
gHFS: BOOLEAN;
gInd: STRING[10];
gInfected: BOOLEAN;
gInfectedWritten: BOOLEAN;
gOption: TMainOpt;
gPgmrname: Str255;
gReportFlags: TFeedbackRec;
gScreenFlags: TFeedbackRec;
gSecsBegins: LONGINT;
gSecsEnds: LONGINT;
gSFGetPt: Point;
gSFPutPt: Point;
gSFRep: SFReply;
gTotals: TCountsRec;
gZZGlobals: SignedByte;
FUNCTION Code0IsValid
: BOOLEAN;
PROCEDURE CommentBegins;
PROCEDURE CommentFgPrRsrc
(pRsrcPtr: TRsrcPtr);
PROCEDURE CommentRsrcBegins
(pRsrcPtr: TRsrcPtr);
PROCEDURE DirectoryBegins;
PROCEDURE DirectoryEnds;
PROCEDURE ErrorBegins
(pStr: Str255);
PROCEDURE ErrorEnds
(pBeeps: INTEGER);
PROCEDURE ErrorOSErr
(pStr: Str255);
PROCEDURE GetRsrc
(pRsrcPtr: TRsrcPtr;
pResType: ResType;
pInt: INTEGER;
pIntIs: TResIdOrIndex);
PROCEDURE InitGlobals;
PROCEDURE InitRsrc
(pRsrcPtr: TRsrcPtr);
FUNCTION JTEIsValid
(pJTEPtr: TJTEPtr)
: BOOLEAN;
PROCEDURE ListCounts
(pPtr: TCountsPtr);
PROCEDURE LookForKnownViruses;
PROCEDURE PauseBriefly;
PROCEDURE PatrolBegins;
PROCEDURE PatrolEnds;
PROCEDURE ProcessCurrRsrc;
PROCEDURE ProcessFile;
PROCEDURE ReleaseRsrc
(pRsrcPtr: TRsrcPtr);
PROCEDURE ShortHexDump
(pPtr: Ptr;
pNbrBytes: SignedByte);
PROCEDURE Trace
(pStr: Str255);
PROCEDURE TraceNbr
(pStr: Str255;
pNbr: LONGINT);
PROCEDURE ZeroOut
(pStart: Ptr;
pCount: Size);
PROCEDURE ZeroOutRange
(p1: Ptr;
p2: Ptr);
{*******************************************}
IMPLEMENTATION
{$R-}
PROCEDURE ExitSecurityPatrol; EXTERNAL;
PROCEDURE Wryte
(pStr: Str255); EXTERNAL;
PROCEDURE WryteChar
(pChar: CHAR); EXTERNAL;
PROCEDURE WryteEoln; EXTERNAL;
PROCEDURE WryteFilename; EXTERNAL;
PROCEDURE WryteFilenameToScreenOnlyForNow;
EXTERNAL;
PROCEDURE WryteLn
(pStr: Str255); EXTERNAL;
PROCEDURE WryteNbr
(pNbr: LONGINT;
pNbrDigits:INTEGER); EXTERNAL;
PROCEDURE WryteType
(pType: ResType); EXTERNAL;
PROCEDURE CallProcPtr
(pProcPtr: ProcPtr);
INLINE
$205F, { MOVE.L (A7)+,A0 }
$4E90; { JSR (A0) }
PROCEDURE ErrorInfected
(pStr: Str255); FORWARD;
PROCEDURE ErrorMsg
(pStr: Str255;
pBeeps: INTEGER); FORWARD;
FUNCTION FixedCode0
(pJTPtr: TJTEPtr)
: BOOLEAN; FORWARD;
PROCEDURE ProcessRsrcs
(pResType: ResType;
pProcPtr: ProcPtr); FORWARD;
FUNCTION RemovedRsrc
(pRsrcPtr: TRsrcPtr)
: BOOLEAN; FORWARD;
PROCEDURE TraceRsrc
(pStr: Str255;
pRsrcPtr: TRsrcPtr); FORWARD;
{$S Fingerprint}
{$I Fingerprint.ipas }
{$S Globals}
{-------------------------------------------}
PROCEDURE AbortPatrolIfCmdPeriodPressed;
BEGIN
WHILE GetNextEvent(gEvtMask,gEvt) DO
WITH gEvt DO
IF (what = nullEvent) THEN
LEAVE
ELSE IF (what = keyDown) THEN
IF (BAnd(modifiers,cmdKey)=cmdKey)
AND (BAnd(message,charCodeMask)=$2E)
THEN
BEGIN
gAbortPatrol := TRUE;
WryteLn('Patrol aborted');
LEAVE;
END;
END;
{-------------------------------------------}
PROCEDURE AwaitKeypress;
BEGIN
WHILE TRUE DO
BEGIN
IF NOT(GetNextEvent(gEvtMask,gEvt)) THEN
CYCLE;
WITH gEvt DO
IF (what = keyDown) THEN
BEGIN
IF (BAnd(modifiers,cmdKey)=cmdKey)
AND (BAnd(message,charCodeMask)=$2E)
THEN
BEGIN
gAbortPatrol := TRUE;
WryteLn('Patrol aborted');
END;
LEAVE;
END;
END;
END;
{-------------------------------------------}
FUNCTION Code0IsValid
: BOOLEAN;
BEGIN
IF gOption[eTrace] THEN
Trace('Code0IsValid');
WITH TJTHdl(gCode0.fHdl)^^ DO
Code0IsValid :=
(gCode0.fSize >= 24) AND
(fAboveA5Size >= 40) AND
(fNbrBytesInTable >= 8) AND
(fTableOffset = 32) AND
(fAboveA5Size = fNbrBytesInTable+32) AND
((fNbrBytesInTable MOD 8) = 0);
END;
{-------------------------------------------}
PROCEDURE CommentBegins;
BEGIN
Wryte(gInd);
Wryte(gInd);
Wryte(gInd);
END;
{-------------------------------------------}
PROCEDURE CommentRsrcBegins
(pRsrcPtr: TRsrcPtr);
BEGIN
CommentBegins;
WITH pRsrcPtr^ DO
BEGIN
WryteType(fResType);
WryteNbr (fResId,7);
Wryte (' (');
ShortHexDump(Ptr(ORD4(@fResAttrs)+1),1);
WryteChar(')');
END;
END;
{-------------------------------------------}
PROCEDURE CountInfected;
BEGIN
IF gOption[eTrace] THEN
Trace('CountInfected');
INC(gCounts.fInfected);
INC(gTotals.fInfected);
END;
{-------------------------------------------}
PROCEDURE DirectoryBegins;
BEGIN
IF gOption[eTrace] THEN
Trace('DirectoryBegins');
gReportFlags.fWroteDirname := FALSE;
gScreenFlags.fWroteDirname := FALSE;
END;
{-------------------------------------------}
PROCEDURE DirectoryEnds;
BEGIN
IF gOption[eTrace] THEN
Trace('DirectoryEnds');
(*
Wryte ('End of ');
WryteLn(gCurrDirname);
*)
END;
{-------------------------------------------}
FUNCTION Disinfected_nVIR
: BOOLEAN;
VAR
snVIR2: TRsrcRec;
sCodeGone: BOOLEAN;
BEGIN
IF gOption[eTrace] THEN
Trace('Disinfected_nVIR');
Disinfected_nVIR := FALSE;
InitRsrc(@snVIR2);
GetRsrc (@snVIR2,'nVIR',2,ResId);
WITH snVIR2 DO
BEGIN
IF (fFlag <> kRsrcHdlValid) THEN
BEGIN
ErrorInfected('No nVIR 2!');
ReleaseRsrc(@gCurrRsrc);
EXIT(Disinfected_nVIR);
END;
IF (fSize < 8) THEN
BEGIN
ErrorInfected('Too small nVIR 2!');
ReleaseRsrc(@gCurrRsrc);
ReleaseRsrc(@snVIR2);
EXIT(Disinfected_nVIR);
END;
MoveHHi(fHdl);
HLock (fHdl);
IF NOT(FixedCode0(TJTEPtr(fHdl^))) THEN
BEGIN
ReleaseRsrc(@gCurrRsrc);
ReleaseRsrc(@snVIR2);
EXIT(Disinfected_nVIR);
END;
Disinfected_nVIR := TRUE;
sCodeGone := RemovedRsrc(@gCurrRsrc);
ReleaseRsrc(@snVIR2);
ProcessRsrcs('nVIR',@ProcessRemoveRsrc);
IF sCodeGone
AND (Count1Resources('nVIR') = 0) THEN
ErrorMsg('nVIR removed',0)
ELSE
BEGIN
ErrorMsg('nVIR “disinfected”:',0);
CommentBegins;
Wryte ('All of its resources are now ');
Wryte ('harmless, but some were not ');
WryteLn('removed, for some reason.');
END;
END;
END;
{-------------------------------------------}
FUNCTION Disinfected_Scores
: BOOLEAN;
BEGIN
IF gOption[eTrace] THEN
Trace('Disinfected_Scores');
Disinfected_Scores := FALSE;
WITH gCurrRsrc DO
BEGIN
MoveHHi(fHdl);
HLock (fHdl);
WITH TScoresHdl(fHdl)^^ DO
IF NOT(FixedCode0(@fOldJTE)) THEN
BEGIN
ReleaseRsrc(@gCurrRsrc);
EXIT(Disinfected_Scores);
END;
Disinfected_Scores := TRUE;
IF RemovedRsrc(@gCurrRsrc) THEN
ErrorMsg('Scores removed',0)
ELSE
ErrorMsg('Scores disinfected',0);
END;
END;
{-------------------------------------------}
PROCEDURE ErrorBegins
(pStr: Str255);
BEGIN
WryteFilename;
Wryte (gInd);
Wryte (gInd);
Wryte (pStr);
END;
{-------------------------------------------}
PROCEDURE ErrorEnds
(pBeeps: INTEGER);
VAR
i: INTEGER;
sBeeps: INTEGER;
BEGIN
IF gOption[eBeeps] THEN
BEGIN
IF (pBeeps > 4) THEN
sBeeps := 4
ELSE
sBeeps := pBeeps;
FOR i := 1 TO sBeeps DO
SysBeep(3);
END;
IF gOption[eAwait] THEN
BEGIN
WryteLn(' (WAITING ON KEY PRESS)');
AwaitKeypress;
END
ELSE
WryteEoln;
END;
{-------------------------------------------}
PROCEDURE ErrorInfected
(pStr: Str255);
BEGIN
IF NOT(gInfectedWritten) THEN
BEGIN
ErrorBegins('**!INFECTED!** ');
WryteEoln;
gInfectedWritten := TRUE;
END;
IF (pStr <> '') THEN
BEGIN
CommentBegins;
Wryte(pStr);
ErrorEnds(3);
END;
END;
{-------------------------------------------}
PROCEDURE ErrorMsg
(pStr: Str255;
pBeeps: INTEGER);
BEGIN
ErrorBegins(pStr);
ErrorEnds(pBeeps);
END;
{-------------------------------------------}
PROCEDURE ErrorOSErr
(pStr: Str255);
BEGIN
IF (pStr <> '') THEN
BEGIN
ErrorBegins(pStr);
WryteEoln;
END;
CommentBegins;
Wryte ('OSErr code = ');
WryteNbr(gError,1);
ErrorEnds(2);
END;
{-------------------------------------------}
FUNCTION FixedCode0
(pJTPtr: TJTEPtr)
: BOOLEAN;
BEGIN
FixedCode0 := FALSE;
IF gOption[eTrace] THEN
Trace('FixedCode0');
IF NOT(JTEIsValid(pJTPtr)) THEN
BEGIN
ErrorInfected('Bad Jump Table Entry!');
EXIT(FixedCode0);
END;
IF NOT(gOption[eRmVir]) THEN
BEGIN
ErrorInfected('Remove option off');
CommentBegins;
WITH pJTPtr^ DO
BEGIN
Wryte ('Jumps to ');
WryteNbr(fOffset,1);
Wryte (' of CODE ');
WryteNbr(fSegId,1);
WryteEoln;
END;
ErrorMsg('Not removed',1);
EXIT(FixedCode0);
END;
WITH gCode0 DO
BEGIN
IF gOption[eTrace] THEN
BEGIN
Trace('About to restore CODE 0');
AbortPatrolIfCmdPeriodPressed;
IF gAbortPatrol THEN
EXIT(FixedCode0);
END;
TJTHdl(fHdl)^^.fJTEntry[1] := pJTPtr^;
IF (BAnd(fResAttrs,resProtected) <> 0)
AND (fResAttrs <> -1) THEN
BEGIN
SetResAttrs(fHdl,0);
ChangedResource(fHdl);
gError := ResError;
SetResAttrs(fHdl,fResAttrs);
END
ELSE
BEGIN
ChangedResource(fHdl);
gError := ResError;
END;
IF (gError <> NoErr) THEN
BEGIN
ErrorInfected('CODE 0 unchanged!');
IF (gError = wPrErr) THEN
ErrorMsg('Disk is locked',0)
ELSE
ErrorOSErr('');
gError := 0;
EXIT(FixedCode0);
END;
WriteResource(fHdl);
gError := ResError;
IF (gError <> NoErr) THEN
BEGIN
ErrorInfected('CODE 0 unwritten!');
ErrorOSErr('');
EXIT(FixedCode0);
END;
END;
FixedCode0 := TRUE;
END;
{-------------------------------------------}
PROCEDURE GetRsrc
(pRsrcPtr: TRsrcPtr;
pResType: ResType;
pInt: INTEGER;
pIntIs: TResIdOrIndex);
VAR
sName: Str255;
sResLoad: BOOLEAN;
{----------------------}
PROCEDURE CommentWhich;
BEGIN
CommentBegins;
WryteType(pResType);
WryteChar(' ');
WryteNbr (pInt,1);
IF (pIntIs = Index) THEN
Wryte (' (indexed)');
WryteEoln;
END;
{----------------------}
BEGIN
WITH pRsrcPtr^ DO
BEGIN
IF (fFlag <> kRsrcIsInitd) THEN
BEGIN
ErrorMsg('Logic error using GetRsrc',4);
AwaitKeypress;
ExitSecurityPatrol;
END;
fResType := pResType;
fResId := pInt;
sResLoad := (TWordPtr(kResLoad)^ <> 0);
IF (gActiveSelf OR gActiveSys) THEN
SetResLoad(FALSE);
IF (pIntIs = Index) THEN
BEGIN
IF gOption[eTrace] THEN
TraceRsrc('About to get ind',pRsrcPtr);
fHdl := Get1IndResource(pResType,pInt);
END
ELSE
BEGIN
IF gOption[eTrace] THEN
TraceRsrc('About to get',pRsrcPtr);
fHdl := Get1Resource(pResType,pInt);
END;
IF sResLoad THEN
BEGIN
IF (gActiveSelf OR gActiveSys) THEN
SetResLoad(TRUE);
IF (fHdl = NIL)
OR (ORD4(fHdl) = -1) THEN
BEGIN
gError := ResError;
ErrorOSErr('Couldn’t get resource');
CommentWhich;
InitRsrc(pRsrcPtr);
EXIT(GetRsrc);
END;
fFlag := kRsrcHdlValid;
fResAttrs := GetResAttrs(fHdl);
IF (ResError <> NoErr) THEN
fResAttrs := -1;
IF (fHdl^ = NIL) THEN
BEGIN
LoadResource(fHdl);
fLoaded := eWeLoadedIt;
IF gOption[eTrace] THEN
Trace('We loaded it');
END
ELSE
BEGIN
fLoaded := eAlreadyLoaded;
IF gOption[eTrace] THEN
Trace('Already loaded');
END;
IF (fHdl^ = NIL) THEN
BEGIN
gError := ResError;
IF (gError <> NoErr) THEN
BEGIN
ErrorMsg('Couldn’t load resource',0);
IF (gError = memFullErr) THEN
ErrorMsg('No room in heap zone',1)
ELSE
ErrorOSErr('');
CommentWhich;
ReleaseRsrc(pRsrcPtr);
EXIT(GetRsrc);
END;
END;
fSize := SizeResource(fHdl);
END
ELSE
BEGIN
fFlag := kRsrcHdlValid;
fSize := MaxSizeRsrc(fHdl);
fLoaded := eNotYet;
IF gOption[eTrace] THEN
Trace('No-load get, loaded not yet');
END;
IF (pIntIs = Index) THEN
BEGIN
GetResInfo(fHdl,fResId,fResType,sName);
gError := ResError;
IF (gError <> NoErr) THEN
BEGIN
ErrorOSErr('Couldn’t get resource id');
CommentWhich;
ReleaseRsrc(pRsrcPtr);
EXIT(GetRsrc);
END;
END;
IF sResLoad THEN
BEGIN
fState := HGetState(fHdl);
IF ((fResType = 'CODE')
AND (fResId = 0)) THEN
BEGIN
MoveHHi(fHdl);
HLock (fHdl);
END
ELSE
HNoPurge(fHdl);
END;
END;
IF gOption[eTrace] THEN
TraceRsrc('Got',pRsrcPtr);
INC(gCounts.fResources);
INC(gTotals.fResources);
END;
{-------------------------------------------}
PROCEDURE InitGlobals;
VAR
sGetHdl: DialogTHndl;
sGetSize: Point;
sPutHdl: DialogTHndl;
sPutSize: Point;
sScrnSize: Point;
BEGIN
ZeroOutRange(@gAAGlobals,@gZZGlobals);
gCurrIOBuffer := NewPtr(kIOBufferSize);
InitRsrc(@gCode0);
InitRsrc(@gCurrRsrc);
gEvtMask :=
everyEvent - (updateMask + activMask);
GetPort(gGrafPtr);
gInd := ' ';
sGetHdl :=
DialogTHndl(GetResource('DLOG',getDlgID));
IF (sGetHdl = NIL)
OR (LONGINT(sGetHdl) = -1) THEN
SetPt(sGetSize,304,104)
ELSE
BEGIN
IF (sGetHdl^ = NIL) THEN
LoadResource(Handle(sGetHdl));
sGetSize := sGetHdl^^.boundsRect.botRight;
ReleaseResource(Handle(sGetHdl));
END;
sPutHdl :=
DialogTHndl(GetResource('DLOG',putDlgID));
IF (sPutHdl = NIL)
OR (LONGINT(sPutHdl) = -1) THEN
SetPt(sPutSize,348,136)
ELSE
BEGIN
IF (sPutHdl^ = NIL) THEN
LoadResource(Handle(sPutHdl));
sPutSize := sPutHdl^^.boundsRect.botRight;
ReleaseResource(Handle(sPutHdl));
END;
WITH gGrafPtr^.portBits.bounds DO
BEGIN
sScrnSize.h := right-left;
sScrnSize.v := bottom-top;
END;
gSFGetPt.h := (sScrnSize.h-sGetSize.h) DIV 2;
gSFGetPt.v := (sScrnSize.v-sGetSize.v) DIV 2;
gSFPutPt.h := (sScrnSize.h-sPutSize.h) DIV 2;
gSFPutPt.v := (sScrnSize.v-sPutSize.v) DIV 2;
END;
{-------------------------------------------}
PROCEDURE InitRsrc
(pRsrcPtr: TRsrcPtr);
BEGIN
ZeroOut(Ptr(pRsrcPtr),SIZEOF(TRsrcRec));
pRsrcPtr^.fFlag := kRsrcIsInitd;
END;
{-------------------------------------------}
FUNCTION JTEIsValid
(pJTEPtr: TJTEPtr)
: BOOLEAN;
VAR
sCode: TRsrcRec;
BEGIN
IF gOption[eTrace] THEN
Trace('JTEIsValid');
JTEIsValid := FALSE;
WITH pJTEPtr^, sCode DO
BEGIN
InitRsrc(@sCode);
SetResLoad(FALSE);
GetRsrc(@sCode,'CODE',fSegId,ResId);
SetResLoad(TRUE);
IF (fFlag <> kRsrcHdlValid) THEN
EXIT(JTEIsValid);
JTEIsValid :=
(fSkip3F3C = $3F3C) AND
(fSegId > 0) AND
(fSkipA9F0 = -22032) AND { $A9F0 }
(fSize > 0);
ReleaseRsrc(@sCode);
END;
END;
{-------------------------------------------}
PROCEDURE ListCounts
(pPtr: TCountsPtr);
BEGIN
IF gOption[eTrace] THEN
Trace('CountsListing');
WITH pPtr^ DO
BEGIN
WryteLn ('Files:');
WryteNbr(fFiles, 6);
WryteLn (' processed');
WryteNbr(fExamined,6);
WryteLn (' examined');
WryteNbr(fDeleted, 6);
WryteLn (' deleted');
WryteLn ('Resources:');
WryteNbr(fResources,6);
WryteLn (' processed');
WryteNbr(fInfected, 6);
WryteLn (' infected');
WryteNbr(fRemoved, 6);
WryteLn (' removed');
Wryte ('Currently available memory is ');
WryteNbr(MemAvail DIV 1024,1);
WryteLn ('K.');
PauseBriefly;
END;
END;
{-------------------------------------------}
PROCEDURE LookForKnownViruses;
VAR
sWeUsedToBeInfected: BOOLEAN;
{--------------------}
PROCEDURE Get1stCode;
BEGIN
WITH TJTHdl(gCode0.fHdl)^^.fJTEntry[1] DO
BEGIN
GetRsrc(@gCurrRsrc,'CODE',fSegId,ResId);
IF (gCurrRsrc.fFlag<>kRsrcHdlValid) THEN
BEGIN
ErrorInfected('Couldn’t get 1st CODE');
InitRsrc(@gCurrRsrc);
EXIT(LookForKnownViruses);
END;
END;
END;
{--------------------}
BEGIN
IF gOption[eTrace] THEN
Trace('LookForKnownViruses');
sWeUsedToBeInfected := FALSE;
Get1stCode;
WITH gCurrRsrc DO
BEGIN
LookForVirus_nVIR;
IF fInfected THEN
BEGIN
CountInfected;
IF fKnown AND (fSize = 372) THEN
ErrorInfected('nVIR 372 virus')
ELSE IF fKnown AND (fSize = 422) THEN
ErrorInfected('nVIR 422 virus')
ELSE
BEGIN
ErrorInfected('New nVIR virus!');
gFgPrTitle := '';
CommentFgPrRsrc(@gCurrRsrc);
END;
IF Disinfected_nVIR THEN
sWeUsedToBeInfected := TRUE;
Get1stCode;
END;
LookForVirus_Scores;
IF fKnown AND fInfected THEN
BEGIN
CountInfected;
ErrorInfected('Scores virus');
IF Disinfected_Scores THEN
sWeUsedToBeInfected := TRUE;
END
ELSE
ReleaseRsrc(@gCurrRsrc);
END;
IF sWeUsedToBeInfected THEN
LookForKnownViruses;
END;
{-------------------------------------------}
PROCEDURE PatrolBegins;
BEGIN
IF gOption[eTrace] THEN
Trace('PatrolBegins');
WryteEoln;
WryteLn('*******************************');
ZeroOut(@gCounts,SIZEOF(TCountsRec));
GetDateTime(gSecsBegins);
END;
{-------------------------------------------}
PROCEDURE PatrolEnds;
VAR
sMins: INTEGER;
sSecs: INTEGER;
BEGIN
GetDateTime(gSecsEnds);
sSecs := gSecsEnds - gSecsBegins;
sMins := sSecs DIV 60;
sSecs := sSecs - (sMins * 60);
WryteEoln;
WryteLn('*******************************');
WryteEoln;
Wryte ('End of patrol that took ');
WryteNbr(sMins,1);
WryteChar(':');
IF (sSecs < 10) THEN
BEGIN
WryteChar('0');
WryteNbr (sSecs,1);
END
ELSE
WryteNbr (sSecs,2);
WryteEoln;
ListCounts(@gCounts);
END;
{-------------------------------------------}
PROCEDURE PauseBriefly;
VAR
sTicks: LONGINT;
BEGIN
Delay(120,sTicks);
END;
{-------------------------------------------}
PROCEDURE ProcessCodes;
VAR
i: INTEGER;
sNbrEntries: INTEGER;
sPrevId: INTEGER;
sWeirdCode0: BOOLEAN;
{------------------------}
PROCEDURE CommentWhere;
BEGIN
CommentBegins;
Wryte ('At entry ');
WryteNbr(i,1);
WryteEoln;
END;
{------------------------}
BEGIN
IF gOption[eTrace] THEN
Trace('ProcessCodes');
GetRsrc(@gCode0,'CODE',0,ResId);
IF (gCode0.fFlag <> kRsrcHdlValid) THEN
BEGIN
ErrorMsg('Code rsrcs without CODE 0',1);
EXIT(ProcessCodes);
END;
IF NOT(Code0IsValid) THEN
BEGIN
ErrorMsg('Unexpected CODE 0 values',1);
ReleaseRsrc(@gCode0);
EXIT(ProcessCodes);
END;
LookForKnownViruses;
WITH TJTHdl(gCode0.fHdl)^^ DO
BEGIN
sNbrEntries := fNbrBytesInTable DIV 8;
sPrevId := 1;
sWeirdCode0 :=
(COPY(gCurrFilename,1,9)='Red Ryder') OR
(COPY(gCurrFilename,1,6)='Canvas' ) OR
(COPY(gCurrFilename,1,9)='PageMaker');
FOR i := 1 TO sNbrEntries DO
WITH fJTEntry[i] DO
BEGIN
IF (fSkip3F3C = $3F3C)
AND (fSegId = sPrevId)
AND (fSkipA9F0 = -22032) THEN
CYCLE;
AbortPatrolIfCmdPeriodPressed;
IF gAbortPatrol THEN
LEAVE;
IF NOT(JTEIsValid(@fJTEntry[i])) THEN
BEGIN
ErrorMsg('CODE 0 has invalid JTE',1);
CommentWhere;
LEAVE;
END;
IF sWeirdCode0 THEN
BEGIN
sPrevId := fSegId;
CYCLE;
END;
IF (fSegId < sPrevId) THEN
BEGIN
ErrorMsg('JT not ascending',1);
CommentWhere;
LEAVE;
END;
INC(sPrevId);
IF (fSegId = sPrevId) THEN
CYCLE;
ErrorMsg('JT skips ResId',1);
CommentWhere;
LEAVE;
END;
END;
ReleaseRsrc(@gCode0);
END;
{-------------------------------------------}
PROCEDURE ProcessFile;
VAR
sSaveC1T: INTEGER;
{----------------------------}
PROCEDURE ExitIfCantReadFork;
BEGIN
IF (gError <> NoErr) THEN
BEGIN
IF (gError = eofErr) THEN
{ no resource fork }
ELSE IF (gError = fnfErr) THEN
ErrorMsg('File not found',1)
ELSE IF (gError = nsvErr) THEN
ErrorMsg('No such volume',1)
ELSE IF (gError = opWrErr) THEN
ErrorMsg(CONCAT('Already in use. ',
'(Don’t use under MultiFinder!)'),1)
ELSE
ErrorOSErr('Couldn’t open file');
gError := NoErr;
EXIT(ProcessFile);
END;
END;
{----------------------------}
BEGIN
IF gOption[eTrace] THEN
Trace('ProcessFile');
AbortPatrolIfCmdPeriodPressed;
IF gAbortPatrol THEN
EXIT(ProcessFile);
INC(gCounts.fFiles);
INC(gTotals.fFiles);
gInfected := FALSE;
gInfectedWritten := FALSE;
gReportFlags.fWroteFilename := FALSE;
gScreenFlags.fWroteFilename := FALSE;
IF gOption[eLList] THEN
WryteFilename
ELSE
WryteFilenameToScreenOnlyForNow;
IF (LENGTH(gCurrFilename) > 0) THEN
IF (gCurrFilename[1] = '.') THEN
BEGIN
ErrorMsg('Filename begins with “.”',1);
EXIT(ProcessFile);
END;
IF gActiveSelf AND NOT(kProcessSelf) THEN
EXIT(ProcessFile);
gCurrEOF := -1;
gError := FSOpen(gCurrFilename,gCurrWDRefNum,
gCurrRefNum);
ExitIfCantReadFork;
gError := GetEOF(gCurrRefNum,gCurrEOF);
IF (gError = NoErr) THEN
BEGIN
WITH gCurrFInfo DO
IF (COPY(gCurrFilename,1,7)='MacsBug')
OR (fdType = 'RELB')
OR (fdType = 'OBJ ') THEN
IF NOT(KnownDataFork) THEN
CommentFgPrData;
gError := FSClose(gCurrRefNum);
IF (gError <> NoErr) THEN
ErrorOSErr('Couldn’t close data fork');
END
ELSE
ErrorOSErr('Couldn’t GetEOF');
IF gActiveSelf THEN
BEGIN
gCurrRefNum := TWordPtr(kCurApRefNum)^;
gError := NoErr;
END
ELSE IF gActiveSys THEN
BEGIN
gCurrRefNum := TWordPtr(kSysMap)^;
gError := NoErr;
END
ELSE
BEGIN
SetResLoad(FALSE);
gCurrRefNum := OpenRFPerm(gCurrFilename,
gCurrWDRefNum,
fsRdWrPerm);
gError := ResError;
SetResLoad(TRUE);
ExitIfCantReadFork;
END;
IF (gCurrRefNum <> CurResFile) THEN
BEGIN
UseResFile(gCurrRefNum);
gError := ResError;
IF (gError <> NoErr) THEN
BEGIN
ErrorOSErr('Couldn’t use resource fork');
gError := NoErr;
EXIT(ProcessFile);
END;
END;
INC(gCounts.fExamined);
INC(gTotals.fExamined);
IF (Count1Resources('CODE') > 0) THEN
ProcessCodes;
gFgPrTitle := 'Unknown Resource(s):';
ProcessRsrcs('ADBS',@Process_ADBS);
ProcessRsrcs('CACH',@Process_CACH);
ProcessRsrcs('CDEF',@Process_CDEF);
ProcessRsrcs('DATA',@Process_DATA);
ProcessRsrcs('DRVR',@Process_DRVR);
ProcessRsrcs('DSAT',@Process_DSAT);
ProcessRsrcs('FKEY',@Process_FKEY);
ProcessRsrcs('FMTR',@Process_FMTR);
ProcessRsrcs('INIT',@Process_INIT);
ProcessRsrcs('LDEF',@Process_LDEF);
ProcessRsrcs('MBDF',@Process_MBDF);
ProcessRsrcs('MDEF',@Process_MDEF);
ProcessRsrcs('MMAP',@Process_MMAP);
ProcessRsrcs('NBPC',@Process_NBPC);
ProcessRsrcs('PACK',@Process_PACK);
ProcessRsrcs('PDEF',@Process_PDEF);
ProcessRsrcs('PTCH',@Process_PTCH);
ProcessRsrcs('ROv#',@Process_ROvList);
ProcessRsrcs('ROvr',@Process_ROvr);
ProcessRsrcs('SERD',@Process_SERD);
ProcessRsrcs('WDEF',@Process_WDEF);
ProcessRsrcs('XCMD',@Process_XCMD);
ProcessRsrcs('XFCN',@Process_XFCN);
ProcessRsrcs('atpl',@Process_atpl);
ProcessRsrcs('boot',@Process_boot);
ProcessRsrcs('cdev',@Process_cdev);
ProcessRsrcs('mppc',@Process_mppc);
ProcessRsrcs('snth',@Process_snth);
ProcessRsrcs('view',@Process_view);
IF gOption[eFgPr] THEN
BEGIN
gFgPrTitle := 'Fingerprint(s):';
ProcessRsrcs('ADBS',@ProcessCurrRsrc);
ProcessRsrcs('CACH',@ProcessCurrRsrc);
ProcessRsrcs('CDEF',@ProcessCurrRsrc);
IF gOption[eFgPrC] THEN
ProcessRsrcs('CODE',@ProcessCurrRsrc);
ProcessRsrcs('DATA',@ProcessCurrRsrc);
ProcessRsrcs('DRVR',@ProcessCurrRsrc);
ProcessRsrcs('DSAT',@ProcessCurrRsrc);
ProcessRsrcs('FKEY',@ProcessCurrRsrc);
ProcessRsrcs('FMTR',@ProcessCurrRsrc);
ProcessRsrcs('INIT',@ProcessCurrRsrc);
ProcessRsrcs('LDEF',@ProcessCurrRsrc);
ProcessRsrcs('MBDF',@ProcessCurrRsrc);
ProcessRsrcs('MDEF',@ProcessCurrRsrc);
ProcessRsrcs('MMAP',@ProcessCurrRsrc);
ProcessRsrcs('NBPC',@ProcessCurrRsrc);
ProcessRsrcs('PACK',@ProcessCurrRsrc);
ProcessRsrcs('PDEF',@ProcessCurrRsrc);
ProcessRsrcs('PTCH',@ProcessCurrRsrc);
ProcessRsrcs('ROv#',@ProcessCurrRsrc);
ProcessRsrcs('ROvr',@ProcessCurrRsrc);
ProcessRsrcs('SERD',@ProcessCurrRsrc);
ProcessRsrcs('WDEF',@ProcessCurrRsrc);
ProcessRsrcs('XCMD',@ProcessCurrRsrc);
ProcessRsrcs('XFCN',@ProcessCurrRsrc);
ProcessRsrcs('atpl',@ProcessCurrRsrc);
ProcessRsrcs('boot',@ProcessCurrRsrc);
ProcessRsrcs('cdev',@ProcessCurrRsrc);
ProcessRsrcs('mppc',@ProcessCurrRsrc);
ProcessRsrcs('snth',@ProcessCurrRsrc);
ProcessRsrcs('view',@ProcessCurrRsrc);
ProcessRsrcs('nVIR',@ProcessCurrRsrc);
END;
IF gActiveSelf OR gActiveSys THEN
EXIT(ProcessFile);
sSaveC1T := Count1Types;
CloseResFile(gCurrRefNum);
IF NOT(gInfected) THEN
EXIT(ProcessFile);
WITH gCurrFInfo DO
BEGIN
IF ((gCurrFilename = 'Note Pad File')
OR (gCurrFilename = 'Scrapbook File'))
AND (fdCreator = 'ZSYS')
AND gOption[eRmVir] THEN
BEGIN
fdType := 'ZSYS';
fdCreator := 'MACS';
fdFlags := 4096;
gError := SetFInfo(gCurrFilename,
gCurrWDRefNum,
gCurrFInfo);
IF (gError = NoErr) THEN
ErrorMsg('Reset to system document',0)
ELSE
ErrorOSErr('FInfo not reset');
EXIT(ProcessFile);
END;
END;
IF (gCurrEOF <> 0) THEN
BEGIN
ErrorMsg('File still has data fork',0);
ErrorMsg('File not deleted',1);
EXIT(ProcessFile);
END;
IF (sSaveC1T <> 0) THEN
BEGIN
ErrorMsg('File still has resources',0);
ErrorMsg('File not deleted',1);
EXIT(ProcessFile);
END;
ErrorMsg('File emptied',0);
gError :=
FSDelete(gCurrFilename,gCurrWDRefNum);
IF (gError = NoErr) THEN
BEGIN
gCurrFileDeleted := TRUE;
INC(gCounts.fDeleted);
INC(gTotals.fDeleted);
ErrorMsg('File deleted',1);
END
ELSE
ErrorOSErr('File not deleted');
END;
{-------------------------------------------}
PROCEDURE ProcessRsrcs
(pResType: ResType;
pProcPtr: ProcPtr);
VAR
i: INTEGER;
sIdx: INTEGER;
BEGIN
IF gOption[eTrace] THEN
Trace('ProcessRsrcs');
WITH gCurrRsrc DO
BEGIN
sIdx := 1;
FOR i := 1 TO Count1Resources(pResType) DO
BEGIN
AbortPatrolIfCmdPeriodPressed;
IF gAbortPatrol THEN
LEAVE;
GetRsrc(@gCurrRsrc,pResType,sIdx,Index);
IF (fFlag <> kRsrcHdlValid) THEN
BEGIN
INC(sIdx);
CYCLE;
END;
CallProcPtr(pProcPtr);
IF fInfected THEN
BEGIN
CountInfected;
ErrorInfected('');
CommentRsrcBegins(@gCurrRsrc);
WryteLn(' is an infection');
IF RemovedRsrc(@gCurrRsrc) THEN
BEGIN
ErrorMsg('Removed',0);
CYCLE;
END;
ErrorMsg('Not removed',1);
INC(sIdx);
CYCLE;
END;
IF NOT(fKnown) THEN
CommentFgPrRsrc(@gCurrRsrc);
ReleaseRsrc(@gCurrRsrc);
INC(sIdx);
END;
END;
END;
{-------------------------------------------}
PROCEDURE ReleaseRsrc
(pRsrcPtr: TRsrcPtr);
BEGIN
WITH pRsrcPtr^ DO
BEGIN
IF (fFlag <> kRsrcHdlValid) THEN
BEGIN
ErrorMsg('Error using ReleaseRsrc',4);
AwaitKeypress;
ExitSecurityPatrol;
END;
IF gOption[eTrace] THEN
TraceRsrc('About to release',pRsrcPtr);
IF (gActiveSelf OR gActiveSys) THEN
IF gOption[eTrace] THEN
Trace('Not Released')
ELSE
ELSE
BEGIN
HSetState(fHdl,fState);
ReleaseResource(fHdl);
IF gOption[eTrace] THEN
Trace('Released');
END;
InitRsrc(pRsrcPtr);
END;
END;
{-------------------------------------------}
FUNCTION RemovedRsrc
(pRsrcPtr: TRsrcPtr)
: BOOLEAN;
VAR
sBits0and7:LONGINT;
{--------------------}
PROCEDURE ExitIfError
(pStr: Str255);
BEGIN
gError := ResError;
IF (gError <> NoErr) THEN
BEGIN
ErrorMsg(pStr,0);
IF (gError = wPrErr) THEN
ErrorMsg('Disk is locked',0)
ELSE
ErrorOSErr('');
CommentRsrcBegins(pRsrcPtr);
WryteLn(' not removed');
ReleaseRsrc(pRsrcPtr);
EXIT(RemovedRsrc);
END;
END;
{--------------------}
BEGIN
RemovedRsrc := FALSE;
IF gOption[eTrace] THEN
Trace('RemovedRsrc');
AbortPatrolIfCmdPeriodPressed;
IF gAbortPatrol
OR NOT(gOption[eRmVir]) THEN
BEGIN
ReleaseRsrc(pRsrcPtr);
EXIT(RemovedRsrc);
END;
WITH pRsrcPtr^ DO
BEGIN
IF (fFlag <> kRsrcHdlValid) THEN
BEGIN
ErrorMsg('Error using RemovedRsrc',4);
AwaitKeypress;
ExitSecurityPatrol;
END;
IF gOption[eTrace] THEN
BEGIN
TraceRsrc('About to remove',pRsrcPtr);
AbortPatrolIfCmdPeriodPressed;
IF gAbortPatrol THEN
EXIT(RemovedRsrc);
END;
IF NOT(fInfected) THEN
BEGIN
ErrorMsg('Tried to remove uninfected',4);
AwaitKeypress;
ExitSecurityPatrol;
END;
IF kZeroOutVirs AND (fHdl^ <> NIL) THEN
BEGIN
ZeroOut(fHdl^,fSize);
ChangedResource(fHdl);
gError := ResError;
IF (gError = NoErr) THEN
BEGIN
WriteResource(fHdl);
gError := ResError;
IF (gError <> NoErr) THEN
ErrorOSErr('Couldn’t WriteResource');
END
ELSE
ErrorOSErr('Couldn’t ChangedResource');
END;
sBits0and7 := BAnd(fResAttrs,$81);
SetResAttrs(fHdl,LoWord(sBits0and7));
RmveResource(fHdl);
ExitIfError('Couldn’t remove resource');
UpdateResFile(gCurrRefNum);
ExitIfError('Couldn’t update res file');
DisposHandle(fHdl);
InitRsrc(pRsrcPtr);
RemovedRsrc := TRUE;
IF gOption[eTrace] THEN
Trace('RemovedRsrc successful');
END;
INC(gCounts.fRemoved);
INC(gTotals.fRemoved);
END;
{-------------------------------------------}
PROCEDURE ShortHexDump
(pPtr: Ptr;
pNbrBytes: SignedByte);
VAR
i: INTEGER;
sCh1,sCh2: LONGINT;
sDigit: LONGINT;
sIdx: Ptr;
BEGIN
sIdx := pPtr;
FOR i := 1 TO pNbrBytes DO
BEGIN
sDigit := ORD4(sIdx^);
sCh1 := BSR(BAnd(sDigit,$F0),4);
sCh2 := BAnd(sDigit,$0F);
IF sCh1 > 9 THEN
WryteChar(CHR(sCh1 + $37))
ELSE
WryteChar(CHR(sCh1 + $30));
IF sCh2 > 9 THEN
WryteChar(CHR(sCh2 + $37))
ELSE
WryteChar(CHR(sCh2 + $30));
INC(LONGINT(sIdx));
END;
END;
{-------------------------------------------}
PROCEDURE Trace
(pStr: Str255);
BEGIN
ErrorBegins(pStr);
ErrorEnds(0);
END;
{-------------------------------------------}
PROCEDURE TraceNbr
(pStr: Str255;
pNbr: LONGINT);
BEGIN
ErrorBegins(pStr);
WryteNbr(pNbr,1);
ErrorEnds(0);
END;
{-------------------------------------------}
PROCEDURE TraceRsrc
(pStr: Str255;
pRsrcPtr: TRsrcPtr);
BEGIN
ErrorBegins(pStr);
WITH pRsrcPtr^ DO
BEGIN
WryteChar(' ');
WryteType(fResType);
WryteNbr (fResId,7);
END;
ErrorEnds(0);
END;
{-------------------------------------------}
PROCEDURE ZeroOut
(pStart: Ptr;
pCount: Size);
VAR
i: INTEGER;
sIdx: Ptr;
BEGIN
sIdx := pStart;
FOR i := 1 TO pCount DO
BEGIN
sIdx^ := 0;
INC(LONGINT(sIdx));
END;
END;
{-------------------------------------------}
PROCEDURE ZeroOutRange
(p1: Ptr;
p2: Ptr);
VAR
i: INTEGER;
sIdx: Ptr;
BEGIN
IF (ORD4(p1) < ORD4(p2)) THEN
sIdx := p1
ELSE
sIdx := p2;
FOR i := 1 TO ABS(ORD4(p2)-ORD4(p1))+1 DO
BEGIN
sIdx^ := 0;
INC(LONGINT(sIdx));
END;
END;
{*******************************************}
END.